package com.example.lotterysystem.service.activitystatus.impl;

import com.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.service.ActivityService;
import com.example.lotterysystem.service.activitystatus.ActivityStatusManager;
import com.example.lotterysystem.service.activitystatus.operator.AbstractActivityOperator;
import com.example.lotterysystem.service.dto.ConvertActivityStatusDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@Component
public class ActivityStatusManagerImpl implements ActivityStatusManager {

    private static final Logger logger = LoggerFactory.getLogger(ActivityStatusManagerImpl.class);

    @Autowired
    private final Map<String, AbstractActivityOperator> operatorMap = new HashMap<>();

    @Autowired
    private ActivityService activityService;


    @Override
    // 因为这边设计到多个表的操作，当抛出异常时应该把之前的都回滚掉
    @Transactional(rollbackFor = Exception.class)
    public void handlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        // 1、活动状态有依赖性，依赖奖品/人员状态，如果添加其他模块，代码更新多。导致代码维护性差
        // 2、状态扭转条件可能会扩展，当前写法扩展性差

        // 判断operator是不是空
        if (CollectionUtils.isEmpty(operatorMap)) {
            logger.warn("operatorMap 为空");
            return;
        }

        // 定义map规定顺序 map<String,AbstractActivityOperator>
        Map<String,AbstractActivityOperator> currentMap = new HashMap<>(operatorMap);
        Boolean update = false;

        // 先处理：人员、奖品
        update = processConvertStatus(convertActivityStatusDTO,currentMap,1);

        // 后处理：活动
        update = processConvertStatus(convertActivityStatusDTO,currentMap,2) || update;

        // 更新缓存
        if (update) {
            activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
        }
    }

    @Override
    public void rollbackHandlerEvent(ConvertActivityStatusDTO convertActivityStatusDTO) {
        // 回滚 operatorMap：活动、奖品、人员
        // 活动是否需要回滚？？ 需要！
        // 原因：奖品恢复为INIT状态，就说明这个活动下的奖品绝对没有抽完，所以要变成running状态
        for (AbstractActivityOperator operator: operatorMap.values()) {
            // 无需判断，直接转换
            operator.convert(convertActivityStatusDTO);
        }

        // 都回滚之后进行缓存更新
        activityService.cacheActivity(convertActivityStatusDTO.getActivityId());
    }

    /**
     * 扭转状态
     *
     * @param convertActivityStatusDTO
     * @param currentMap
     * @param sequence
     * @return
     */
    private Boolean processConvertStatus(ConvertActivityStatusDTO convertActivityStatusDTO,
                                         Map<String, AbstractActivityOperator> currentMap,
                                         int sequence) {
        Boolean update = false;

        // 遍历currentMap
        Iterator<Map.Entry<String,AbstractActivityOperator>> iterator = currentMap.entrySet().iterator();
        while (iterator.hasNext()) {
            AbstractActivityOperator operator = iterator.next().getValue();
            // Operator是否需要转换
             // 不需要转换
            if (operator.sequence() != sequence
                    || !operator.needConvert(convertActivityStatusDTO)) {
                continue;
            }
             // 需要则进行转换操作
            if (!operator.convert(convertActivityStatusDTO)) {
                // 转换失败
                logger.error("{} 状态转换失败! ",operator.getClass().getName());
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_STATUS_CONVERT_ERROR);
            }

            // 走到这里说明转换成功了
            // currentMap 删除当前 Operator
            iterator.remove();
            update = true;
        }

        // 返回
        return update;
    }
}
